package com.yupi.yupicturebackend.aop;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.yupi.yupicturebackend.annotation.DataValidation;
import com.yupi.yupicturebackend.exception.BusinessException;
import com.yupi.yupicturebackend.exception.ErrorCode;
import com.yupi.yupicturebackend.model.entity.User;
import com.yupi.yupicturebackend.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collection;
import java.util.regex.Pattern;

/**
 * 数据验证切面
 * 用于对方法参数进行统一验证和处理
 * 
 * @author yupi
 */
@Aspect
@Component
@Slf4j
public class DataValidationAspect {

    @Resource
    private UserService userService;

    // 常用正则表达式
    private static final Pattern EMAIL_PATTERN = Pattern.compile(
            "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
    private static final Pattern PHONE_PATTERN = Pattern.compile(
            "^1[3-9]\\d{9}$");
    private static final Pattern URL_PATTERN = Pattern.compile(
            "^(https?|ftp)://[^\\s/$.?#].[^\\s]*$");
    private static final Pattern SQL_INJECTION_PATTERN = Pattern.compile(
            "(?i)(union|select|insert|update|delete|drop|create|alter|exec|script)", Pattern.CASE_INSENSITIVE);
    private static final Pattern XSS_PATTERN = Pattern.compile(
            "(?i)<[^>]*script[^>]*>|javascript:|on\\w+\\s*=", Pattern.CASE_INSENSITIVE);

    /**
     * 数据验证切面
     *
     * @param joinPoint 切入点
     * @param dataValidation 数据验证注解
     * @return 方法执行结果
     * @throws Throwable 异常
     */
    @Around("@annotation(dataValidation)")
    public Object doValidation(ProceedingJoinPoint joinPoint, DataValidation dataValidation) throws Throwable {
        // 验证用户登录状态
        if (dataValidation.requireLogin()) {
            validateUserLogin();
        }

        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Parameter[] parameters = method.getParameters();

        // 执行基础验证
        performBasicValidation(args, parameters, dataValidation);

        // 执行自定义验证规则
        performCustomValidation(args, parameters, dataValidation);

        // 执行安全检查
        performSecurityCheck(args, dataValidation);

        // 验证通过，执行目标方法
        return joinPoint.proceed();
    }

    /**
     * 验证用户登录状态
     */
    private void validateUserLogin() {
        try {
            RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            User loginUser = userService.getLoginUser(request);
            if (loginUser == null) {
                throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
            }
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
    }

    /**
     * 执行基础验证
     *
     * @param args 方法参数
     * @param parameters 参数信息
     * @param dataValidation 验证注解
     */
    private void performBasicValidation(Object[] args, Parameter[] parameters, DataValidation dataValidation) {
        for (int i = 0; i < args.length; i++) {
            Object arg = args[i];
            Parameter parameter = parameters[i];
            String paramName = parameter.getName();

            // 验证参数非空
            if (dataValidation.validateNotNull() && arg == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, 
                        String.format("参数 %s 不能为空", paramName));
            }

            if (arg != null) {
                // 验证字符串参数非空白
                if (dataValidation.validateNotBlank() && arg instanceof String) {
                    String strArg = (String) arg;
                    if (StrUtil.isBlank(strArg)) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, 
                                String.format("参数 %s 不能为空白字符串", paramName));
                    }
                }

                // 验证集合参数非空
                if (dataValidation.validateNotEmpty() && arg instanceof Collection) {
                    Collection<?> collectionArg = (Collection<?>) arg;
                    if (CollUtil.isEmpty(collectionArg)) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, 
                                String.format("参数 %s 不能为空集合", paramName));
                    }
                }
            }
        }
    }

    /**
     * 执行自定义验证规则
     *
     * @param args 方法参数
     * @param parameters 参数信息
     * @param dataValidation 验证注解
     */
    private void performCustomValidation(Object[] args, Parameter[] parameters, DataValidation dataValidation) {
        DataValidation.ValidationRule[] rules = dataValidation.rules();
        if (rules.length == 0) {
            return;
        }

        for (DataValidation.ValidationRule rule : rules) {
            String paramName = rule.param();
            
            // 查找对应的参数
            Object paramValue = null;
            for (int i = 0; i < parameters.length; i++) {
                if (parameters[i].getName().equals(paramName)) {
                    paramValue = args[i];
                    break;
                }
            }

            if (paramValue == null) {
                continue;
            }

            // 执行验证规则
            validateByRule(paramValue, rule);
        }
    }

    /**
     * 根据规则验证参数
     *
     * @param paramValue 参数值
     * @param rule 验证规则
     */
    private void validateByRule(Object paramValue, DataValidation.ValidationRule rule) {
        String value = rule.value();
        String errorMessage = StrUtil.isNotBlank(rule.message()) ? rule.message() : "参数验证失败";

        switch (rule.type()) {
            case MIN_LENGTH:
                if (paramValue instanceof String) {
                    String str = (String) paramValue;
                    int minLength = Integer.parseInt(value);
                    if (str.length() < minLength) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, errorMessage);
                    }
                }
                break;
            case MAX_LENGTH:
                if (paramValue instanceof String) {
                    String str = (String) paramValue;
                    int maxLength = Integer.parseInt(value);
                    if (str.length() > maxLength) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, errorMessage);
                    }
                }
                break;
            case REGEX:
                if (paramValue instanceof String) {
                    String str = (String) paramValue;
                    if (!ReUtil.isMatch(value, str)) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, errorMessage);
                    }
                }
                break;
            case EMAIL:
                if (paramValue instanceof String) {
                    String str = (String) paramValue;
                    if (!EMAIL_PATTERN.matcher(str).matches()) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, errorMessage);
                    }
                }
                break;
            case PHONE:
                if (paramValue instanceof String) {
                    String str = (String) paramValue;
                    if (!PHONE_PATTERN.matcher(str).matches()) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, errorMessage);
                    }
                }
                break;
            case URL:
                if (paramValue instanceof String) {
                    String str = (String) paramValue;
                    if (!URL_PATTERN.matcher(str).matches()) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, errorMessage);
                    }
                }
                break;
            case RANGE:
                if (paramValue instanceof Number) {
                    Number num = (Number) paramValue;
                    String[] range = value.split(",");
                    if (range.length == 2) {
                        double min = Double.parseDouble(range[0]);
                        double max = Double.parseDouble(range[1]);
                        double val = num.doubleValue();
                        if (val < min || val > max) {
                            throw new BusinessException(ErrorCode.PARAMS_ERROR, errorMessage);
                        }
                    }
                }
                break;
        }
    }

    /**
     * 执行安全检查
     *
     * @param args 方法参数
     * @param dataValidation 验证注解
     */
    private void performSecurityCheck(Object[] args, DataValidation dataValidation) {
        for (Object arg : args) {
            if (arg instanceof String) {
                String strArg = (String) arg;
                
                // SQL注入检查
                if (dataValidation.sqlInjectionCheck() && SQL_INJECTION_PATTERN.matcher(strArg).find()) {
                    log.warn("检测到潜在的SQL注入攻击: {}", strArg);
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数包含非法字符");
                }
                
                // XSS攻击检查
                if (dataValidation.xssCheck() && XSS_PATTERN.matcher(strArg).find()) {
                    log.warn("检测到潜在的XSS攻击: {}", strArg);
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数包含非法脚本");
                }
            }
        }
    }
}
